﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

namespace Engine
{
    public class Scene : Microsoft.Xna.Framework.DrawableGameComponent
    {
        Engine.Entity toolbox;
        double ToolboxStartedOn;
        Effects.SinusoidalTween BoxTween = new Effects.SinusoidalTween(200, 200, 0);

        /// <summary>
        /// Drives all the layers of the scene
        /// </summary>
        public Dictionary<int, UI.TileEngine.TileLayer> layers = new Dictionary<int, UI.TileEngine.TileLayer>();

        /// <summary>
        /// Drives all the tilesets of the scene
        /// </summary
        public Dictionary<String, UI.TileEngine.Tileset> tilesets = new Dictionary<String, UI.TileEngine.Tileset>();

        /// <summary>
        /// Provides access to the keyboard state and keyboard events
        /// </summary>
        public KeyboardState prevState;

        /// <summary>
        /// Provides access to the mouse state and mouse events
        /// </summary>
        public Input.Mouse mouse;

        /// <summary>
        /// Contains the spriteBatch on which we will write our stuff
        /// </summary>
        SpriteBatch spriteBatch;

        /// <summary>
        /// Builds the component
        /// </summary>
        /// <param name="game"></param>
        public Scene(Game game)
            : base(game)
        {
        }

        /// <summary>
        /// Loads content into the compoenent
        /// </summary>
        protected override void LoadContent()
        {

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(this.Game.GraphicsDevice);

            //Load the keyboard state
            prevState = Keyboard.GetState();

            // TODO: use this.Content to load your game content here
            this.tilesets.Add("embroidings2gold", new UI.TileEngine.Tileset(Texture2D.FromStream(this.Game.GraphicsDevice, System.IO.File.OpenRead(@"..\..\..\..\..\..\Content\2D textures\Remade\floors\carpets\embroidings2gold.png")), new Point(32, 32)));
            this.tilesets.Add("carpet1red", new UI.TileEngine.Tileset(Texture2D.FromStream(this.Game.GraphicsDevice, System.IO.File.OpenRead(@"..\..\..\..\..\..\Content\2D textures\Remade\floors\carpets\carpet1red.png")), new Point(32, 32)));

            //Create the layers
            this.layers.Add(0, new UI.TileEngine.TileLayer(256, 256));
            this.layers.Add(1, new UI.TileEngine.TileLayer(256, 256));

            //Load the tilelayer
            this.tilesets["embroidings2gold"].SetTiles(new Rectangle(0, 0, 4, 4), this.layers[1]);
            this.tilesets["carpet1red"].SetTiles(new Rectangle(0, 0, 4, 4), this.layers[0]);

            //Affect to see if the drawing engine works fine
            this.layers[0].setTile(new Point(2, 2), null);
            this.layers[1].setTile(new Point(2, 2), null);
            this.layers[0].setTile(new Point(3, 2), null);
            this.layers[1].setTile(new Point(3, 2), null);
            this.layers[0].setTile(new Point(3, 3), null);
            this.layers[1].setTile(new Point(3, 3), null);
            this.layers[0].setTile(new Point(3, 4), null);
            this.layers[1].setTile(new Point(3, 4), null);

            //Create the background texture for the dialog boxes
            Texture2D dialogWindowBg = new Texture2D(this.Game.GraphicsDevice, 32, 32);
            Color[] dialogWindowBgData = new Color[32 * 32];
            for (int i = 0; i < dialogWindowBgData.Length; i++)
            {
                dialogWindowBgData[i] = Color.Black;
            }
            dialogWindowBg.SetData<Color>(dialogWindowBgData);

            //Create the toolbox
            toolbox = new Engine.Entity(dialogWindowBg, new Rectangle(this.Game.GraphicsDevice.Viewport.Width, 0, 200, this.Game.GraphicsDevice.Viewport.Height));
            Engine.MouseEvent ToolBoxOverlayEvent = new Engine.MouseEvent();
            ToolBoxOverlayEvent.triggerOnZone = true;
            ToolBoxOverlayEvent.triggerZone = toolbox.positionSize;
            //ToolBoxOverlayEvent.effects.Add(new Effects.AddOverlayEffect(toolbox, "hoverOverlay", Effects.FrameOverlay.get(graphics.GraphicsDevice, new Rectangle(GraphicsDevice.Viewport.Width, 0, 200, GraphicsDevice.Viewport.Height), Color.Yellow, 4)));
            toolbox.events.Add("mouseover", ToolBoxOverlayEvent);

            //Create the mouse
            mouse = new Input.Mouse(
                Texture2D.FromStream(this.Game.GraphicsDevice, System.IO.File.OpenRead(@"..\..\..\..\..\..\Content\2D textures\Remade\ui\cursors\yellow-pointer.png")),
                new Vector2(
                    this.Game.GraphicsDevice.Viewport.Bounds.Center.X,
                    this.Game.GraphicsDevice.Viewport.Bounds.Center.Y
                ),
                this.Game.GraphicsDevice.Viewport.Bounds
            );

            //Call the base now that we have everything initialized
            base.LoadContent();

        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Game.Exit();
            }

            //Start the mouse cycle
            mouse.Begin();
            mouse.Update();

            // TODO: Add your update logic here
            KeyboardState newState = Keyboard.GetState();
            if (newState.IsKeyUp(Keys.M) && prevState.IsKeyDown(Keys.M))
            {
                toolbox.visible = true;
                ToolboxStartedOn = gameTime.TotalGameTime.TotalMilliseconds;
                if (BoxTween.startValue == 200)
                {
                    BoxTween = new Effects.SinusoidalTween(200, 0, 200);
                }
                else
                {
                    BoxTween = new Effects.SinusoidalTween(200, 200, -200);
                }
            }
            if (newState.IsKeyUp(Keys.C) && prevState.IsKeyDown(Keys.C))
            {
                mouse.Constraint = !mouse.Constraint;
            }
            if (newState.IsKeyUp(Keys.B) && prevState.IsKeyDown(Keys.B))
            {
                mouse.ForceHardwareMousePosition = !mouse.ForceHardwareMousePosition;
            }
            prevState = newState;


            if (gameTime.TotalGameTime.TotalMilliseconds - ToolboxStartedOn > BoxTween.duration)
            {
                Rectangle position = toolbox.positionSize;
                position.X = this.Game.GraphicsDevice.Viewport.Width - (int)BoxTween.changeValue;
                toolbox.positionSize = position;
            }
            else
            {
                Rectangle position = toolbox.positionSize;
                position.X = this.Game.GraphicsDevice.Viewport.Width - (int)BoxTween.tweenValue(gameTime.TotalGameTime.TotalMilliseconds - ToolboxStartedOn);
                toolbox.positionSize = position;
            }

            //End the mouse cycle
            mouse.End();

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            this.Game.GraphicsDevice.Clear(Color.White);

            // TODO: Add your drawing code here
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);

            //Draw the layers
            foreach (UI.TileEngine.TileLayer layer in this.layers.Values)
            {
                layer.draw(new Rectangle(0, 0, 20, 20), spriteBatch);
            }

            //Draw the dialog box
            toolbox.Draw(spriteBatch);

            //Draw the mouse
            mouse.Draw(spriteBatch);

            //End of the sprite batch
            spriteBatch.End();

        }

    }
}
